﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using RAP.Framework.Libary.Configuration;
using RAP.Framework.Libary.DomTemplateBuilder;
using RAP.Framework.Libary.Utils;
using System.Threading.Tasks;
using RAP.Framework.Libary.DataSource.Model;

namespace RAP.Web.Libary.Common
{
  /// <summary>
  /// 扩展
  /// </summary>
  public static class Extensions
	{
		/// <summary>
		/// 获取客户端IP地址
		/// </summary>
		/// <param name="context"></param>
		/// <returns></returns>
		public static string GetIPAddress( this HttpContext context )
		{
			return context.Request.Headers[ "X-Forwarded-For" ].FirstOrDefault().IsNullOrEmptyValue( ( ) => context.Connection.RemoteIpAddress.ToString() );
		}

		/// <summary>
		/// 通过HttpRequest获取依赖服务对象
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="request"></param>
		/// <returns></returns>
		public static T GetService<T>( this HttpRequest request )
		{
			return request.HttpContext.GetService<T>();
		}

		/// <summary>
		/// 通过HttpRequest获取依赖服务对象
		/// </summary>
		/// <param name="request"></param>
		/// <param name="type"></param>
		/// <returns></returns>
		public static T GetService<T>( this HttpRequest request, Type type )
		{
			return ( T )request.HttpContext.GetService<T>( type );
		}

		/// <summary>
		/// 通过HttpContext获取依赖服务对象
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="context"></param>
		/// <returns></returns>
		public static T GetService<T>( this HttpContext context )
		{
			return context.RequestServices.GetService<T>();
		}

		/// <summary>
		/// 通过HttpContext获取依赖服务对象
		/// </summary>
		/// <param name="context"></param>
		/// <param name="type"></param>
		/// <returns></returns>
		public static T GetService<T>( this HttpContext context, Type type )
		{
			return ( T )context.RequestServices.GetService( type );
		}


		/// <summary>
		/// 使用配置管理
		/// </summary>
		/// <param name="app"></param>
		/// <param name="url"></param>
		/// <param name="enableWatcher"></param>
		public static void UseConfiguration( this IApplicationBuilder app, string url, bool enableWatcher = true )
		{
			ConfigurationManager.AppSettings.Config( url.MapPath(), enableWatcher );

		}

		/// <summary>
		/// 使用模板管理
		/// </summary>
		/// <param name="app"></param>
		/// <param name="url"></param>
		/// <param name="enableWatcher"></param>
		public static void UseDomTemplate( this IApplicationBuilder app, string url, bool enableWatcher = true )
		{
			DomTemplateManager.Instance.Create( url.MapPath(), enableWatcher );
		}

		/// <summary>
		/// 控制器重定向
		/// </summary>
		/// <param name="context">上下文对象</param>
		/// <param name="url">重定向地址</param>
		/// <returns></returns>
		public static ActionExecutingContext Redirect( this ActionExecutingContext context, string url )
		{
			context.Result = new RedirectResult( url );
			return context;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="exp"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static HtmlString ToHtml( this string exp, string defaultValue = null )
		{
			if ( exp.IsNullOrEmpty() )
			{
				exp = defaultValue;
			}
			return new HtmlString( exp );
		}

		/// <summary>
		/// 将键值对象中指定key的值封装为HtmlString对象
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="key"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static HtmlString ToHtml( this IDictionary obj, string key, string defaultValue = null )
		{
			return obj.ToString( key, defaultValue ).HtmlDecode().ToHtml();
		}

		/// <summary>
		/// 解码HTML字符串
		/// </summary>
		/// <param name="html"></param>
		/// <returns></returns>
		public static string HtmlDecode( this string html )
		{
			if ( html.IsNullOrEmpty() )
			{
				return null;
			}
			return WebUtility.HtmlDecode( html );
		}

		/// <summary>
		/// 编码HTML字符串
		/// </summary>
		/// <param name="html"></param>
		/// <returns></returns>
		public static string HtmlEncode( this string html )
		{
			if ( html.IsNullOrEmpty() )
			{
				return null;
			}
			return WebUtility.HtmlEncode( html );
		}

		/// <summary>
		/// 获取数字参数
		/// </summary>
		/// <param name="routeData"></param>
		/// <param name="paramKeys"></param>
		/// <returns></returns>
		public static IDictionary GetInt32Params( this RouteData routeData, string[] paramKeys )
		{
			if ( paramKeys.IsNullOrEmpty() )
			{
				return null;
			}
			IDictionary result = new ListDictionary();
			paramKeys.Map<string>( ( key ) =>
			{
				result.Add( key, routeData.Values.ToInt32( key ) );
				return true;
			} );
			return result;
		}


		/// <summary>
		/// 获取查询参数对象
		/// </summary>
		/// <param name="routeData"></param>
		/// <param name="paramKeys"></param>
		/// <returns></returns>
		public static IDictionary GetParams( this RouteData routeData, string[] paramKeys = null )
		{
			if ( paramKeys.IsNullOrEmpty() )
			{
				return null;
			}
			IDictionary result = new ListDictionary();
			paramKeys.Map<string>( ( key ) =>
			{
				result.Add( key, routeData.Values[ key ] );
				return true;
			} );
			return result;
		}

		/// <summary>
		/// 转换键值对的数据类型
		/// </summary>
		/// <param name="parameterTypes"></param>
		/// <param name="key"></param>
		/// <param name="val"></param>
		/// <returns></returns>
		public static object GetTypedValue( this IDictionary<string, Type> parameterTypes, string key, object val )
		{
			if ( parameterTypes == null )
			{
				return val;
			}
			if ( parameterTypes.TryGetValue( key, out Type parameterType ) )
			{
				return val.ConvertValue( parameterType );
			}
			return val;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <param name="parameterTypes"></param>
		/// <param name="headerParams"></param>
		/// <returns></returns>
		public static async Task<T> GetParams<T>( this ActionExecutingContext context, IDictionary<string, Type> parameterTypes = null, params string[] headerParams )
		{
			return await context.HttpContext.Request.GetParams<T>( parameterTypes, headerParams );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="context"></param>
		/// <param name="parameterTypes"></param>
		/// <param name="headerParams"></param>
		/// <returns></returns>
		public static async Task<T> GetParams<T>( this HttpContext context, IDictionary<string, Type> parameterTypes = null, params string[] headerParams )
		{
			return await context.Request.GetParams<T>( parameterTypes, headerParams );
		}

		/// <summary>
		/// 将HttpRequest对象的Body内容转换成IDictionary对象
		/// </summary>
		/// <param name="request"></param>
		/// <param name="parameterTypes"></param>
		/// <param name="headerParams"></param>
		/// <returns></returns>
		public static async Task<T> GetParams<T>( this HttpRequest request, IDictionary<string, Type> parameterTypes = null, params string[] headerParams )
		{

			var body = await request.Body.ReadAllTextAsync();
			var queryParams = request.GetService<T>() as IDictionary;
			foreach ( string key in request.Query.Keys )
			{
				var val = request.Query[ key ].ToString();
				queryParams[ key ] = parameterTypes.GetTypedValue( key, val );
			}
			if ( headerParams.IsNotNullOrEmpty() )
			{
				foreach ( string headerName in headerParams )
				{
					var headerVal = request.Headers[ headerName ].ToString();
					if ( headerVal.IsNotNullOrEmpty() && headerVal != "null" )
					{
						queryParams[ headerName ] = parameterTypes.GetTypedValue( headerName, headerVal );
					}
				}
			}
			//获取路由参数

			foreach ( var item in request.HttpContext.GetRouteData()?.Values )
			{
				queryParams[ item.Key ] = item.Value;
			}

			if ( body.IsNullOrEmpty() )
			{
				return ( T )queryParams;
			}
			if ( body.IsNotNullOrEmpty() && body.StartsWith( "<xml>" ) )
			{
				queryParams[ FieldConsts.XMLContentField ] = body;
				return ( T )queryParams;
			}
			var result = body.ToDictionary();
			if ( result == null )
			{
				result = new ListDictionary();
				body.Split( '\r', '&' ).Map<string>( ( item ) =>
				{
					var idx = item.IndexOf( '=' );
					if ( idx > 0 )
					{
						result.Add( item.Substring( 0, idx ), item.Substring( idx + 1 ) );
					}
					else
					{
						result.Add( result.Count, item );
					}
					return true;
				} );
			}
			if ( result != null && parameterTypes.Count > 0 )
			{
				foreach ( string key in result.Keys )
				{
					result[ key ] = parameterTypes.GetTypedValue( key, result[ key ] );
				}
			}
			result.CopyTo( queryParams );
			return ( T )queryParams;
		}

		/// <summary>
		/// 将指定的IDictionary对象转换成ContentResult
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public static ContentResult ToHttpResult( this IDictionary obj )
		{
			return new ContentResult() { Content = obj.ToJSON(), ContentType = "application/json" };
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="queryResult"></param>
		/// <returns></returns>
		public static bool HasError( this IQueryResult queryResult )
		{
			return queryResult?.HasError ?? true;
		}

		/// <summary>
		/// 返回第一个结果集的第一条记录
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetFirstResult( this object obj, object defaultValue = null )
		{
			if ( obj is IDictionary )
			{
				var dict = obj as IDictionary;
				if ( dict.Count == 1 )
				{
					return obj.GetFirstList().First( defaultValue );
				}
			}
			return obj.GetValue( "0" ).IsNullValue( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="queryResult"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetFirstResult( this IQueryResult queryResult, object defaultValue = null )
		{
			return ( ( object )queryResult.Data ).GetFirstResult( defaultValue );
		}

		/// <summary>
		/// 返回第一个结果集的第一条记录
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static T GetFirstResult<T>( this object obj, T defaultValue = default( T ) )
		{
			if ( obj is IDictionary )
			{
				var dict = obj as IDictionary;
				if ( dict.Count == 1 )
				{
					return obj.GetFirstList().First( defaultValue );
				}
			}
			return ( T )obj.GetValue( "0" ).IsNullValue<T>( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="queryResult"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static T GetFirstResult<T>( this IQueryResult queryResult, T defaultValue = default( T ) )
		{
			return ( ( object )queryResult.Data ).GetFirstResult<T>( defaultValue );
		}

		/// <summary>
		/// 返回指定结果集的第一条记录的指定属性
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="key"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetResultValue( this object obj, string key, string resultAlias = "0", object defaultValue = null )
		{
			return obj.GetValue( $"{resultAlias}.0.{key}" ).IsNullValue( defaultValue );
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="queryResult"></param>
		/// <param name="key"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetResultValue( this IQueryResult queryResult, string key, string resultAlias = "0", object defaultValue = null )
		{
			return ( ( object )queryResult.Data ).GetResultValue( key, resultAlias, defaultValue );
		}

		/// <summary>
		/// 返回指定结果集的第一条记录的指定属性
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj"></param>
		/// <param name="key"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static T GetResultValue<T>( this object obj, string key, string resultAlias = "0", T defaultValue = default( T ) )
		{
			return obj.GetValue<T>( $"{resultAlias}.0.{key}" ).IsNullValue<T>( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="queryResult"></param>
		/// <param name="key"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>

		public static T GetResultValue<T>( this IQueryResult queryResult, string key, string resultAlias = "0", T defaultValue = default( T ) )
		{
			return ( ( object )queryResult.Data ).GetResultValue<T>( key, resultAlias, defaultValue );
		}

		/// <summary>
		/// 返回第一个结果集的第一条记录的指定属性
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="key"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetFirstResultValue( this object obj, string key, object defaultValue = null )
		{
			if ( obj is IDictionary )
			{
				var dict = obj as IDictionary;
				if ( dict.Count == 1 )
				{
					return obj.GetFirstResult().GetValue( key ).IsNullValue( defaultValue );
				}
			}
			return obj.GetValue( $"0.{key}" ).IsNullValue( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="queryResult"></param>
		/// <param name="key"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetFirstResultValue( this IQueryResult queryResult, string key, object defaultValue = null )
		{
			return ( ( object )queryResult.Data ).GetFirstResultValue( key, defaultValue );
		}

		/// <summary>
		/// 返回第一个结果集的第一条记录的指定属性
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj"></param>
		/// <param name="key"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static T GetFirstResultValue<T>( this object obj, string key, T defaultValue = default( T ) )
		{
			if ( obj is IDictionary )
			{
				var dict = obj as IDictionary;
				if ( dict.Count == 1 )
				{
					return obj.GetFirstResult().GetValue<T>( key ).IsNullValue<T>( defaultValue );
				}
			}
			return obj.GetValue<T>( $"0.{key}" ).IsNullValue<T>( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="queryResult"></param>
		/// <param name="key"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static T GetFirstResultValue<T>( this IQueryResult queryResult, string key, T defaultValue = default( T ) )
		{
			return ( ( object )queryResult.Data ).GetFirstResultValue<T>( key, defaultValue );
		}

		/// <summary>
		/// 返回第一个结果集的第一条记录的id属性
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static int GetFirstResultId( this object obj, int defaultValue = 0 )
		{
			return obj.GetFirstResultValue<int>( FieldConsts.IdField, defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="queryResult"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static int GetFirstResultId( this IQueryResult queryResult, int defaultValue = 0 )
		{
			return ( ( object )queryResult.Data ).GetFirstResultId( defaultValue );
		}

		/// <summary>
		/// 返回指定别名的结果集
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetRecordset( this object obj, string resultAlias = "0", object defaultValue = null )
		{
			return obj.GetValue( resultAlias ).IsNullValue( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="queryResult"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetRecordset( this IQueryResult queryResult, string resultAlias = "0", object defaultValue = null )
		{
			return ( ( object )queryResult.Data ).GetRecordset( resultAlias, defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static T GetRecordset<T>( this object obj, string resultAlias = "0", T defaultValue = default( T ) )
		{
			return ( T )obj.GetValue( resultAlias ).IsNullValue( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="queryResult"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static T GetRecordset<T>( this IQueryResult queryResult, string resultAlias = "0", T defaultValue = default( T ) )
		{
			return ( ( object )queryResult.Data ).GetRecordset<T>( resultAlias, defaultValue );
		}

		/// <summary>
		/// 获取第一个结果集
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetFirstRecordset( this object obj, object defaultValue = null )
		{
			if ( obj is IDictionary )
			{
				var dict = obj as IDictionary;
				if ( dict.Count == 1 )
				{
					return dict[ dict.Keys.FirstItem() ].IsNullValue( defaultValue );
				}
			}
			return obj.GetValue( "0" ).IsNullValue( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="queryResult"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static object GetFirstRecordset( this IQueryResult queryResult, object defaultValue = null )
		{
			return ( ( object )queryResult.Data ).GetFirstRecordset( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static T GetFirstRecordset<T>( this object obj, T defaultValue = default( T ) )
		{
			if ( obj is IDictionary )
			{
				var dict = obj as IDictionary;
				if ( dict.Count == 1 )
				{
					return dict.ToObject<T>( dict.Keys.FirstItem() ).IsNullValue<T>( defaultValue );
				}
			}
			return ( T )obj.GetValue( "0" ).IsNullValue( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="queryResult"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>

		public static T GetFirstRecordset<T>( this IQueryResult queryResult, T defaultValue = default( T ) )
		{
			return ( ( object )queryResult.Data ).GetFirstRecordset<T>( defaultValue );
		}

		/// <summary>
		/// 获取第一个结果集（列表）
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static IList GetFirstList( this object obj, IList defaultValue = null )
		{
			if ( obj is IList )
			{
				return obj as IList;
			}
			if ( obj is IDictionary )
			{
				var dict = obj as IDictionary;
				if ( dict.Count == 1 )
				{
					return dict.ToList( dict.Keys.FirstItem() ).IsNullValue<IList>( defaultValue );
				}
			}
			return obj.GetValue<IList>( "0" ).IsNullValue<IList>( defaultValue );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="queryResult"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static IList GetFirstList( this IQueryResult queryResult, IList defaultValue = null )
		{
			return ( ( object )queryResult.Data ).GetFirstList( defaultValue );
		}

		/// <summary>
		/// 获取指定别名的结果集，并将集合元素转换成指定T类型
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static IList<T> GetList<T>( this object obj, string resultAlias = null, IList defaultValue = null )
		{
			return obj.GetEnumerable<T>( resultAlias, defaultValue ).ToList();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="queryResult"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static IList<T> GetList<T>( this IQueryResult queryResult, string resultAlias = null, IList defaultValue = null )
		{
			return ( ( object )queryResult.Data ).GetList<T>( resultAlias, defaultValue );
		}

		/// <summary>
		/// 获取指定别名的结果集，并将集合元素转换成指定T类型
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static IEnumerable<T> GetEnumerable<T>( this object obj, string resultAlias = null, IList defaultValue = null )
		{
			return obj.GetRecordset<IList>( resultAlias, defaultValue ).Cast<T>();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="queryResult"></param>
		/// <param name="resultAlias"></param>
		/// <param name="defaultValue"></param>
		/// <returns></returns>
		public static IEnumerable<T> GetEnumerable<T>( this IQueryResult queryResult, string resultAlias = null, IList defaultValue = null )
		{
			return ( ( object )queryResult.Data ).GetEnumerable<T>( resultAlias, defaultValue );
		}

		/// <summary>
		/// 根据指定时间对象计算设备绑定、登录时的时间戳参数
		/// </summary>
		/// <param name="date"></param>
		/// <returns></returns>
		public static string GetTimestamp( this DateTime date )
		{
			return $"{date.Year * 1024}{date.Month * 16}{date.Day * 4}{date.Hour * 32}{date.Minute * 256}".MD5Encrypt( false );
		}
	}
}
